﻿/******************************************************************************
  * Copyright  2023 - LiuKuan
  * All right reserved. See COPYRIGHT for detailed Information.
  *
  * @file       Fact.h
  * @brief
  * @author     <807874484@qq.com>
  * @date       2024/7/19
  * @history
  *****************************************************************************/

#ifndef FACT_H
#define FACT_H

#include <QObject>
#include <QString>
#include <QVariant>
#include <QDebug>
#include <QAbstractListModel>

class Fact : public QObject
{
    Q_OBJECT
public:
    typedef enum {
        valueTypeUint8,
        valueTypeInt8,
        valueTypeUint16,
        valueTypeInt16,
        valueTypeUint32,
        valueTypeInt32,
        valueTypeUint64,
        valueTypeInt64,
        valueTypeFloat,
        valueTypeDouble,
        valueTypeString,
        valueTypeBool,
        valueTypeTimeInSeconds,// HH:MM:SS
        valueTypeCustom,       // QByteArray
    }ValueType_t;
    Q_ENUM(ValueType_t)

    explicit Fact(QString name ,ValueType_t type ,QObject *parent  = nullptr);
    Fact(QObject *parent  = nullptr);
    Fact(const Fact& other, QObject* parent = nullptr);
    const Fact& operator=(const Fact& other);

public:
    Q_PROPERTY(ValueType_t type                   READ type            CONSTANT)
    Q_PROPERTY(QVariant    value                  READ value           WRITE setValue            NOTIFY    valueChanged)
    Q_PROPERTY(QString     valueString            READ valueString                               NOTIFY    valueStringChanged)
    Q_PROPERTY(QString     name                   READ name                                      CONSTANT)
    Q_PROPERTY(int         decimalPlaces          READ decimalPlaces   WRITE setDecimalPlaces    NOTIFY    decimalChanged)
    Q_PROPERTY(QVariant    max                    READ max             WRITE setMax              NOTIFY    maxChanged)
    Q_PROPERTY(QVariant    min                    READ min             WRITE setMin              NOTIFY    minChanged)
    Q_PROPERTY(QString     units                  READ units           WRITE setUnits            NOTIFY    unitsChanged)
    Q_PROPERTY(bool        property               READ property        WRITE setProperty         NOTIFY    propertyChanged)

    ValueType_t type            ()const { return type_; }
    QVariant    value           ()const { return rawValue_; }
    QString     valueString     () ;
    QString     name            ()const { return name_; }
    int         decimalPlaces   ()const { return decimalPlaces_; }
    QVariant    max             ()const { return rawMax_; }
    QVariant    min             ()const { return rawMin_; }
    QString     units           ()const { return units_;}
    bool        property        ()const { return property_;}

    void        setValue        (const QVariant &value);
    void        setDecimalPlaces(int   decimalPlaces);
    void        setMax          (const QVariant & rawMax);
    void        setMin          (const QVariant & rawMin);
    void        setUnits        (const QString  & units);
    void        setProperty     (bool state);
signals:
    void valueChanged(QVariant value);
    void valueStringChanged(QString str);
    void decimalChanged();
    void maxChanged();
    void minChanged();
    void unitsChanged();
    void errorMsg(const QString & error);
    void propertyChanged();
private:


    ValueType_t     type_;
    QVariant        rawValue_;
    QString         name_;
    int             decimalPlaces_;
    QVariant        rawMax_;
    QVariant        rawMin_;
    QString         rawUnits_;
    QString         units_;
    bool            property_;
private:
    template<class T>
    bool isInLimit(const QVariant& variantValue) const {
        return min().value<T>() <= variantValue.value<T>() && variantValue.value<T>() <= max().value<T>();
    }
    bool isInMinLimit(const QVariant& variantValue) const;
    bool isInMaxLimit(const QVariant& variantValue) const;

    QVariant maxForType_      (void) const;
    QVariant minForType_      (void) const;
    QString  variantToString_ (const QVariant& variant, int decimalPlaces) const;

    bool convertAndValidateRaw(const QVariant& rawValue,
                               bool convertOnly,
                               QVariant& typedValue,
                               QString& errorString);
    static const int  kDefaultDecimalPlaces_  = 2;
};

#endif // FACT_H
